#include "FTPack.h"

int cd(SOCKET skt, char *path) {
  char c[BUFFER_SIZE];
  sprintf(c, "CWD %s\r\n", path);
  if(sendB(skt, c) == FTP_FILE_ACTION_COMPLETE) {
    return 0;
  } else {
    return -1;
  }
}

SOCKET cs(char *host, int port) {
  struct hostent *server = gethostbyname(host);
  if(!server) {
    return -1;
  }

  char ip[20];
  int i = 0;
  unsigned char c[4];
  while(server->h_addr_list[i] != NULL) {
    memcpy(&c, server->h_addr_list[i], 4);
    sprintf(ip,"%d.%d.%d.%d", c[0], c[1], c[2], c[3]);
    i++;
  }

  SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
  if(s == SOCKET_ERROR) {
    printf("Create socket error!\n");
  }

  int timeout = 3000;
  setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));

  struct sockaddr_in address;
  address.sin_family = AF_INET;
  address.sin_addr.S_un.S_addr = inet_addr(ip);
  address.sin_port = htons((unsigned short)port);

  if(connect(s, (LPSOCKADDR)&address, sizeof(address)) == SOCKET_ERROR) {
    printf("Can't connect to server IP!\n");
  }

  return s;
}

int dd(SOCKET skt, char *path) {
  char c[BUFFER_SIZE];
  sprintf(c, "RMD %s\r\n", path);
  int i = sendB(skt, c);
  if(i != FTP_FILE_ACTION_COMPLETE) {
    return i;
  } else {
    return 0;
  }
}

int df(SOCKET skt, char *path) {
  char c[BUFFER_SIZE];
  sprintf(c, "DELE %s\r\n", path);
  int i = sendB(skt, c);
  if(i != FTP_FILE_ACTION_COMPLETE) {
    return i;
  } else {
    return 0;
  }
}

int dl(SOCKET skt, char *source, char *target, int *size) {
  char c[BUFFER_SIZE];
  ssize_t st, stWrite;

  FILE *f = fopen(target, "wb");
  if(f == NULL) {
    printf("Can't open the file.\n");
    return -2;
  }

  sendB(skt, "TYPE I\r\n");
  SOCKET s = pasv(skt);
  if(s == -1) {
    fclose(f);
    return -1;
  }

  memset(c, sizeof(c), 0);
  sprintf(c, "RETR %s\r\n", source);
  int i = sendB(skt, c);
  if(i >= 300 || i == 0) {
    fclose(f);
    return i;
  }

  memset(c, sizeof(c), 0);
  while((st = recv(s, c, BUFFER_SIZE, 0)) > 0) {
    stWrite = fwrite(&c, st, 1, f);
    if(stWrite != 1) {
      closesocket(s);
      fclose(f);
      return -3;
    }
    if(size != NULL) {
      *size += stWrite;
    }
  }

  closesocket(s);
  fclose(f);

  memset(c, sizeof(c), 0);
  st = recv(skt, c, sizeof(c), 0);
  c[st] = 0;
  printf("%s\n", c);
  sscanf(c, "%d", &i);
  if(i >= 300) {
    return i;
  }

  return 0;
}

SOCKET login(char *username, char *password, char *ip, int port) {
  WSAStartup(MAKEWORD(2, 2), &winSocket);
  SOCKET s = cs(ip, port);
  if(s == -1) {
    return -1;
  }

  char c[BUFFER_SIZE] = {0};
  fd_set fs;
  FD_ZERO(&fs);
  FD_SET(s, &fs);
  struct timeval tv;
  tv.tv_sec = 2;
  tv.tv_usec = 0;
  while(select(s, &fs, NULL, NULL, &tv) > 0) {
    recv(s, c, sizeof(c), 0);
    printf(c);
  }

  memset(c, sizeof(c), 0);
  sprintf(c, "USER %s\r\n", username);
  sendB(s, c);
  sprintf(c, "PASS %s\r\n", password);
  sendB(s, c);

  return s;
}

int logout(SOCKET skt) {
  int i = sendB(skt, "QUIT\r\n");
  closesocket(skt);
  WSACleanup();

  return i;
}

int ls(SOCKET skt, char *path, char **info, int *size) {
  char c[BUFFER_SIZE];
  int i;
  ssize_t st, stBuffer, stTotal;

  SOCKET s = pasv(skt);
  if(s == -1) {
    return -1;
  }

  memset(c, sizeof(c), 0);
  sprintf(c, "LIST %s\r\n", path);
  i = sendB(skt, c);
  if(i >= 300 || i == 0) {
    return i;
  }

  st = stTotal = 0;
  stBuffer = BUFFER_SIZE;
  char *cBuffer = (char *)malloc(stBuffer);
  while((st = recv(s, c, BUFFER_SIZE, 0)) > 0) {
    if(stTotal + st > stBuffer) {
      stBuffer *= 2;
      char *cr = (char *)malloc(stBuffer);
      memcpy(cr, cBuffer, stTotal);
      free(cBuffer);
      cBuffer = cr;
    }
    memcpy(cBuffer + stTotal, c, st);
    stTotal += st;
  }
  closesocket(s);

  memset(c, sizeof(c), 0);
  st = recv(skt, c, sizeof(c), 0);
  c[st] = 0;
  sscanf(c, "%d", &i);
  if(i != 226) {
    free(cBuffer);
    return i;
  }

  cBuffer[stTotal] = 0;
  *info = cBuffer;
  *size = stTotal;

  return 0;
}

int md(SOCKET skt, char *path) {
  char c[BUFFER_SIZE];
  sprintf(c, "MKD %s\r\n", path);
  int i = sendB(skt, c);
  if(i != FTP_PATH_CREATED) {
    return i;
  } else {
    return 0;
  }
}

SOCKET pasv(SOCKET skt) {
  char c[BUFFER_SIZE], rb[BUFFER_SIZE];
  int addr[6];
  ssize_t st;

  memset(c, sizeof(c), 0);
  sprintf(c, "PASV\r\n");
  if(!sendC(skt, c, rb, &st)) {
    sscanf(rb, "%*[^(](%d,%d,%d,%d,%d,%d)",
           &addr[0], &addr[1], &addr[2], &addr[3],
           &addr[4], &addr[5]);
  }

  memset(c, sizeof(c), 0);
  sprintf(c, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
  return cs(c, addr[4] * 256 + addr[5]);
}

char *pwd(SOCKET skt) {
  static char c[BUFFER_SIZE];
  ssize_t st;
  if(!sendC(skt, "PWD\r\n", c, &st)) {
    sscanf(c, "%*[^\"]\"%[^\"]", &c);
  }

  return c;
}

int rm(SOCKET skt, char *s, char *target) {
  char c[BUFFER_SIZE];
  int i;
  sprintf(c, "RNFR %s\r\n", s);
  i = sendB(skt, c);
  if(i != FTP_FILE_PAUSE) {
    return i;
  }
  sprintf(c, "RNTO %s\r\n", target);
  i = sendB(skt, c);
  if(i != FTP_FILE_ACTION_COMPLETE) {
    return i;
  } else {
    return 0;
  }
}

int sendB(SOCKET skt, char *cmd) {
  char c[BUFFER_SIZE];
  ssize_t st;
  printf("FTP client: %s", cmd);
  int i = sendC(skt, cmd, c, &st);
  printf("FTP server: %s", c);
  if(!i) {
    sscanf(c, "%d", &i);
  }

  return i;
}

int sendC(SOCKET skt, char *cmd, char *rb, ssize_t *size) {
  char c[BUFFER_SIZE];
  ssize_t st;
  if(send(skt, cmd, strlen(cmd), 0) == -1) {
    return -1;
  }
  st = recv(skt, c, sizeof(c), 0);
  if(st < 1) {
    return -2;
  }
  c[st] = 0;
  if(size != NULL) {
    *size = st;
  }
  if(rb != NULL) {
    sprintf(rb, "%s", c);
  }

  return 0;
}

int ud(SOCKET skt) {
  int i = sendB(skt, "CDUP\r\n");
  if(i != FTP_FILE_ACTION_COMPLETE || i != FTP_SUCCESS) {
    return i;
  } else {
    return 0;
  }
}

int ul(SOCKET skt, char *source, char *target, int *size) {
  char c[BUFFER_SIZE];
  ssize_t st, stRead;

  FILE *f = fopen(source, "rb");
  if(f == NULL) {
    printf("Can't open the file.\n");
    return -2;
  }

  sendB(skt, "TYPE I\r\n");
  SOCKET s = pasv(skt);
  if(s == -1) {
    fclose(f);
    return -1;
  }

  memset(c, sizeof(c), 0);
  sprintf(c, "STOR %s\r\n", target);
  int i = sendB(skt, c);
  if(i >= 300 || i == 0) {
    fclose(f);
    return i;
  }

  memset(c, sizeof(c), 0);
  while((st = fread(c, 1, BUFFER_SIZE, f)) > 0) {
    stRead = send(s, c, st, 0);
    if(stRead != st) {
      closesocket(s);
      fclose(f);
      return -3;
    }
    if(size != NULL) {
      *size += stRead;
    }
  }

  closesocket(s);
  fclose(f);

  memset(c, sizeof(c), 0);
  st = recv(skt, c, sizeof(c), 0);
  c[st] = 0;
  sscanf(c, "%d", &i);
  if(i >= 300) {
    return i;
  }

  return 0;
}